{
  Unit with a base class of a GUI Object.
  TGLGUIObject - Contain events interactions;
  	- TGLC2DSprite - Basic 2d GUI, have no render;
        - TGLGUIQuad - a renderable and skinable "brick"
  			- TGLGUICompositeObject;
        		- TGLGUIButton;
            - TGLGUIRadioButton;
            - TGLGUICheckbox;
            - TGLGUIMenuItem;
            - Other "clickable" objects;
            - TGLGUILabel, TGLGUIComponentLabel;
            - TGLGUITextFields
         		- TGLGUITable;
         		- TGLGUIDiagram;
         		- etc.
      - TGLGUIImage;
    - TGLGUILayer - Provides hardware instancing of TGLCustomGuiObject;
    - TGLGUI3DInteractiveLayer - Can contain child or be a child of 3D scene
      object to provide interaction.

  TODO: Events model
  For speed up event's searching create separated listeners list for typical
  gui events, change event model for Abstract Manager's inheritance
}
unit GLGUIBase;

interface

uses
  Classes,
  GLScene,
  GLObjects,
  BaseClasses,
  GLCrossPlatform,
  VectorGeometry,
  VectorTypes,
  GLSGenerics,
  GLGUITokens,
  GLGUIEvent,
  GLGUIState,
  GLGUIUtils,
  GLGUIEventManager,
  GLGUIMouseControl;

type
  TGLGUIEventDispatcher = class
  public
//    procedure DispatchMouseDownEvent(AExternal: Boolean);
//    procedure DispatchMouseUpEvent(AExternal: Boolean);
//    procedure DispatchMouseMoveEvent(AExternal: Boolean);
//    procedure DispatchMouseEnterEvent(AExternal: Boolean);
//    procedure DispatchMouseLeaveEvent(AExternal: Boolean);
  end;

  TGLGUIObject = class(TGLSceneObjectEx)
  protected
    FOnMouseDown: TGLGUIEventListenerBind;
    FOnMouseUp: TGLGUIEventListenerBind;
    FOnMouseMove: TGLGUIEventListenerBind;
    FOnMouseEnter: TGLGUIEventListenerBind;
    FOnMouseLeave: TGLGUIEventListenerBind;
    FOnKeyDown: TGLGUIEventListenerBind;
    FOnStateChange: TGLGUIEvent;
    FEventBehaviour: TGLGUIEventBehaviour;
    FListenersOverwriting: Boolean;
    FCurrentState: TGLGUIState;
    FBasicState: TGLGUIState;
    FIsMouseInside: Boolean;
    FSelected: Boolean;
    FEnabled: Boolean;
    FRegistredEvents: TGLGUIEventsList;
    FRegistredBinds: TGLGUIEventListenersList;
    FRenderMode: TGLGUIRenderMode;
    FLayer: TObject;
    FTransmitWorkState: Boolean;
    FCursorImage: SmallInt;
    FProgressEvent: TGLGUIProgressEvent;
    FID: Cardinal;
    function GetState: TGLGUIState; virtual;
    procedure SetState(const AState: TGLGUIState);  virtual;
    function GetBasicState: TGLGUIState; virtual;
    procedure SetBasicState(const AState: TGLGUIState);  virtual;
    function GetEventBehaviour(): TGLGUIEventBehaviour; virtual;
    procedure SetEventBehaviour(AEventBehaviour: TGLGUIEventBehaviour); virtual;
    function GetEnabled: Boolean; virtual;
    function GetIsOnFocus: Boolean; virtual;
    procedure SetTransmitEnableState(ADoEnable: Boolean); virtual;
    function GetTransmitEnableState: Boolean; virtual;
    procedure SetEnabled(AEnabled: Boolean); virtual;
    function GetListenersOverwriting: Boolean;
    procedure SetListenersOverwriting(AOverwrite: Boolean);
    function GetRenderMode: TGLGUIRenderMode; virtual;
    function GetCursorImage: SmallInt;virtual;
    procedure SetCursorImage(AImage: SmallInt);virtual;
    function GetId: Cardinal; virtual;
    procedure SetID(AID: Cardinal); virtual;
    procedure SetOnMouseDown(AEventListener: TGLGUIEventListener); virtual;
    procedure SetOnMouseUp(AEventListener: TGLGUIEventListener); virtual;
    procedure SetOnMouseMove(AEventListener: TGLGUIEventListener); virtual;
    procedure SetOnMouseEnter(AEventListener: TGLGUIEventListener); virtual;
    procedure SetOnMouseLeave(AEventListener: TGLGUIEventListener); virtual;
    procedure SetOnKeyDown(AEventListener: TGLGUIEventListener); virtual;
    procedure AddEventBind(AEvent: TGLGUIEvent; AListener: TGLGUIEventListener;
      var ABind: TGLGUIEventListenerBind); virtual;
    procedure SetEventState(AEvent: TGLGUIevent; AExternal: Boolean); virtual;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DoProgress(const progressTime: TProgressTimes); override;
    {$IFNDEF FPC}
    procedure AddEventListener<T>(AEventType: TGLGUIEventType;
      AListener: TGLGUIEventListener<T>); overload;
    {$ENDIF}
    procedure AddEventListener(AEventType: TGLGUIEventType;
      AListener: TGLGUIEventListener); overload;
    function AddEventListener(AEvent: TGLGUIEvent;
      AListener: TGLGUIEventListener): TGLGUIEventListenerBind; overload;
    procedure RemoveEventListeners(AEvent: TGLGUIEvent); virtual;
    procedure RemoveEventListener(AEvent: TGLGUIEvent;
      AListener: TGLGUIEventListener); virtual;
    procedure DispatchEvent(AEvent: TGLGUIEventType;
      AExternal: Boolean = True); overload; virtual;
    procedure DispatchEvent(AEvent: TGLGUIEvent;
      AExternal: Boolean = True); overload; virtual;
    procedure DispatchMouseDownEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchMouseUpEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchMouseMoveEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchMouseEnterEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchMouseLeaveEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchMouseWheelEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchKeyDownEvent(const AExternal: Boolean = True); virtual;
    procedure DispatchFocusSet();virtual;
    procedure DispatchFocusUnSet();virtual;
    procedure DispatchHoverSet();virtual;
    procedure DispatchHoverUnSet();virtual;
    procedure Enable; virtual;
    procedure Disable(AKeepState: Boolean = False); virtual;
    procedure SetFocus();
    destructor Destroy(); override;
    property OnMouseDown: TGLGUIEventListener write SetOnMouseDown;
    property OnMouseUp: TGLGUIEventListener write SetOnMouseUp;
    property OnMouseMove: TGLGUIEventListener write SetOnMouseMove;
    property OnMouseEnter: TGLGUIEventListener write SetOnMouseEnter;
    property OnMouseLeave: TGLGUIEventListener write SetOnMouseLeave;
    property OnKeyDown: TGLGUIEventListener write SetOnKeyDown;
    property State: TGLGUIState read GetState write SetState;
    property BasicState: TGLGUIState read GetBasicState write SetBasicState;
    property IsOnFocus: Boolean read GetIsOnFocus;
    property IsMouseInside: Boolean read FIsMouseInside;
    property ListenersOverwriting: Boolean read GetListenersOverwriting write
      SetListenersOverwriting;
    property Selected: Boolean read FSelected;
    property TransmitEnableState: Boolean read GetTransmitEnableState
      write SetTransmitEnableState;
    property StateChangeEvent: TGLGUIevent read FOnStateChange;
    property ProgressEvent: TGLGUIProgressEvent read FProgressEvent;
  published
    property EventBehaviour: TGLGUIEventBehaviour read GetEventBehaviour write
      SetEventBehaviour;
    property Enabled: Boolean read GetEnabled write SetEnabled;
    property CursorImage: SmallInt read GetCursorImage write SetCursorImage;
    property ID: Cardinal read GetID write SetID;
  end;

  TGLGUIObjectClass = class of TGLGUIObject;
  TGLGUIObjects = GList<TGLGUIObject>;
implementation

uses
  GLGUILayer;

constructor TGLGUIObject.Create(AOwner: TComponent);
begin
  if (AOwner is TGLGUILayer) then
    FLayer := AOwner
  else if AOwner is TGLGUIObject then
    FLayer := (AOwner as TGLGUIObject).FLayer;

  inherited;

  if Assigned(FLayer) then
    TGLGUILayer(FLayer).RegisterGUIChild(Self);

  FEventBehaviour := ebStopEvent;
  FIsMouseInside := False;
  FEnabled := True;
  FSelected := False;
  FCurrentState := GLGUIEnabled;
  FBasicState := GLGUIEnabled;
  FListenersOverwriting := False;
  FRegistredEvents := TGLGUIEventsList.Create;
  FRegistredBinds := TGLGUIEventListenersList.Create;

  FOnStateChange := GUIEventManager.GetOrCreateEvent('GUI.StateChanged');
  FCursorImage := 0;

  FProgressEvent := TGLGUIProgressEvent.Create;
end;

procedure TGLGUIObject.DoProgress(const progressTime: TProgressTimes);
begin
  inherited;
  if FEnabled then
  begin
    FProgressEvent.DeltaTime := progressTime.deltaTime;
    FProgressEvent.NewTime := progressTime.newTime;
    FProgressEvent.DispatchEvent(Self);
  end;
end;

{$IFNDEF FPC}
procedure TGLGUIObject.AddEventListener<T>(AEventType: TGLGUIEventType; AListener: TGLGUIEventListener<T>);
var
  vEvent: TGLGUIEvent;
begin
  vEvent := GUIEventManager.GetOrCreateEvent(AEventType);
  AddEventListener(vEvent, TGLGUIEventListener<TGLGUIEvent>(AListener));
end;
{$ENDIF}

procedure TGLGUIObject.AddEventListener(AEventType: TGLGUIEventType; AListener: TGLGUIEventListener);
var
  vEvent: TGLGUIEvent;
begin
  vEvent := GUIEventManager.GetOrCreateEvent(AEventType);
  AddEventListener(vEvent, AListener);
end;

function TGLGUIObject.AddEventListener(AEvent: TGLGUIEvent; AListener: TGLGUIEventListener): TGLGUIEventListenerBind;
var
  vBind: TGLGUIEventListenerBind;
  i: integer;
  vEventExist: Boolean;
begin
  vBind := TGLGUIEventListenerBind.Create;
  vBind.Listener := AListener;
  vBind.Sender := Self;
  AEvent.AddListener(vBind);
  vEventExist := False;
  for i := 0 to FRegistredEvents.Count - 1 do
  begin
    if FRegistredEvents.Items[i] = AEvent then
    begin
      vEventExist := True;
      Break;
    end;
  end;
  if not vEventExist then
    FRegistredEvents.Add(AEvent);
  FRegistredBinds.Add(vBind);
  Result := vBind;
end;

procedure TGLGUIObject.RemoveEventListener(AEvent: TGLGUIEvent; AListener: TGLGUIEventListener);
begin
  AEvent.RemoveListener(AListener);
end;

procedure TGLGUIObject.RemoveEventListeners(AEvent: TGLGUIEvent);
begin
  AEvent.RemoveListeners(FRegistredBinds);
end;

procedure TGLGUIObject.DispatchEvent(AEvent: TGLGUIEventType; AExternal: Boolean = True);
var
  vEvent: TGLGUIEvent;
begin
  vEvent := GUIEventManager.FindEvent(AEvent);
  if Assigned(vEvent) then
    DispatchEvent(vEvent, AExternal);
end;

procedure TGLGUIObject.SetEventState(AEvent: TGLGUIEvent; AExternal: Boolean);
begin
  case FEventBehaviour of
  ebPassEvent:;
  ebStopEvent:
    if not AExternal then
      AEvent.EventPhase := epStoped;
  ebDirectToParent:
  begin
    if Assigned(Parent) and (Parent is TGLGUIObject) then
      AEvent.DispatchEvent(Parent);
    if not AExternal then
      AEvent.EventPhase := epStoped;
  end;
  end;
end;

procedure TGLGUIObject.DispatchEvent(AEvent: TGLGUIEvent; AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchEvent(AEvent, False);

  if FEnabled or AEvent.IgnoreState then
    AEvent.DispatchEvent(Self);
  if AExternal then
    AEvent.EventPhase := epWorking;
end;

procedure TGLGUIObject.DispatchMouseDownEvent(const AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchMouseDownEvent(False);

  with MouseDownEvent do
  begin
    if (EventPhase = epWorking) and FEnabled then
      if PointInObject(VectorMake(X, Y, 0, 0)) then
      begin
        SetEventState(MouseDownEvent, AExternal);
        SetState(GLGUISelected);
        FSelected := True;
        if FEventBehaviour = ebStopEvent then
          if GUIEventManager.FocusedObject <> Self then
            GUIEventManager.FocusedObject := Self;

        DispatchEvent(Self);
      end;
  end;
end;

procedure TGLGUIObject.DispatchMouseUpEvent(const AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchMouseUpEvent(False);

  with MouseUpEvent do
  begin
    if (EventPhase = epWorking) and FEnabled then
    begin
      if PointInObject(VectorMake(X, Y, 0, 0)) then
      begin
        State := GLGUIFocused;
        SetEventState(MouseUpEvent, AExternal);
        if FSelected then
          MouseUpEvent.DispatchEvent(Self);
      end
      else
        if GUIEventManager.FocusedObject = Self then
          GUIEventManager.FocusedObject := nil;
    end;
  end;
  FSelected := False;
end;

procedure TGLGUIObject.DispatchMouseMoveEvent(const AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchMouseMoveEvent(False);

  if MouseMoveEvent.Working and FEnabled then
  begin
    with MouseMoveEvent do
      if PointInObject(VectorMake(X, Y, 0, 0)) then
      begin
        SetEventState(MouseMoveEvent, AExternal);
        if not FIsMouseInside then
        begin
          MouseEnterEvent.Prepare;
          DispatchMouseEnterEvent();
        end;
        MouseMoveEvent.DispatchEvent(Self);
      end
      else if FIsMouseInside then
      begin
        MouseLeaveEvent.Prepare;
        DispatchMouseLeaveEvent(False);
      end;
    end;
end;

procedure TGLGUIObject.DispatchMouseEnterEvent(const AExternal: Boolean = True);
begin
  if FEnabled and MouseEnterEvent.Working then
    case FEventBehaviour of
      ebStopEvent:
      begin
        FIsMouseInside := True;
        case FSelected of
          True:
            if IsOnFocus then
              State := GLGUISelected;
          False:
            State := GLGUIFocused;
        end;
        MouseEnterEvent.DispatchEvent(Self);
        MouseEnterEvent.EventPhase := epStoped;
        GUIEventManager.HighLitedObject := Self;
        end;//ebStop End
      ebPassEvent:
      begin
        FIsMouseInside := True;
        SetState(GLGUIFocused);
        MouseEnterEvent.DispatchEvent(Self);
      end;
      ebDirectToParent:
      begin
        FIsMouseInside := True;
        case FSelected of
          True:
            if (GUIEventManager.FocusedObject = Self) then
              SetState(GLGUISelected);
          False:
            SetState(GLGUIFocused);
        end;

        MouseEnterEvent.DispatchEvent(Self);
        if Assigned(Parent) and (Parent is TGLGUIObject)  then
          MouseEnterEvent.DispatchEvent(Parent);
        MouseEnterEvent.EventPhase := epStoped;
        GUIEventManager.HighLitedObject := Self;
      end;
    end;
end;

procedure TGLGUIObject.DispatchMouseLeaveEvent(const AExternal: Boolean = True);
begin
  case FEventBehaviour of
    ebStopEvent:
    begin
      if AExternal then
      begin
        if MouseLeaveEvent.EventPhase = epWorking then
        begin
          FIsMouseInside := False;
          SetState(GLGUIEnabled);
          MouseLeaveEvent.DispatchEvent(Self);
          MouseLeaveEvent.EventPhase := epStoped;
        end;
      end
      else if FEnabled then
        if GUIEventManager.HighLitedObject = Self then
          GUIEventManager.HighLitedObject := nil;
    end;//ebStop End;
    ebPassEvent:
    begin
      if FEnabled and MouseLeaveEvent.Working then
      begin
        FIsMouseInside := False;
        SetState(GLGUIEnabled);
        MouseLeaveEvent.DispatchEvent(Self);
      end;
    end;
    ebDirectToParent:
    begin
      if AExternal then
      begin
        if MouseLeaveEvent.EventPhase = epWorking then
        begin
          FIsMouseInside := False;
          SetState(GLGUIEnabled);
          MouseLeaveEvent.DispatchEvent(Self);
          if Assigned(Parent) and (Parent is TGLGUIObject) then
            MouseLeaveEvent.DispatchEvent(Parent);
          MouseLeaveEvent.EventPhase := epStoped;
        end;
      end
      else if FEnabled then
        if GUIEventManager.HighLitedObject = Self then
          GUIEventManager.HighLitedObject := nil;
    end;
  end;
end;

procedure TGLGUIObject.DispatchMouseWheelEvent(const AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchMouseWheelEvent(False);

  with MouseWheelEvent do
  begin
    if (EventPhase = epWorking) and FEnabled then
      if PointInObject(VectorMake(X, Y, 0, 0)) then
      begin
        SetEventState(MouseWheelEvent, AExternal);

        DispatchEvent(Self);
      end;
  end;
end;

procedure TGLGUIObject.DispatchKeyDownEvent(const AExternal: Boolean = True);
var
  i: Integer;
begin
  for i := Count - 1 downto 0 do
    if Children[i] is TGLGUIObject then
      (Children[i] as TGLGUIObject).DispatchKeyDownEvent(False);

    with KeyDownEvent do
    begin
      if (EventPhase = epWorking) and FEnabled then
      begin
        if not AExternal then
        begin
          if (GUIEventManager.FocusedObject = Self) then
          begin
            DispatchEvent(Self);
            if FEventBehaviour = ebDirectToParent then
            begin
              if Assigned(Parent) and (Parent is TGLGUIObject) then
                DispatchEvent(Parent);
              if not AExternal then
                EventPhase := epStoped;
            end;
          end;
        end
        else
        begin
          EventPhase := epWorking;
          DispatchEvent(Self);
          Exit;
        end;
      end;
    end;
end;

procedure TGLGUIObject.DispatchFocusSet();
begin
end;

procedure TGLGUIObject.DispatchFocusUnSet();
begin
  State := BasicState;
end;

procedure TGLGUIObject.DispatchHoverSet();
begin
  GLGUICursor.Image := FCursorImage;
end;

procedure TGLGUIObject.DispatchHoverUnSet();
begin
end;

function TGLGUIObject.GetState: TGLGUIState;
begin
  Result := FCurrentState;
end;

procedure TGLGUIObject.SetState(const AState: TGLGUIState);
begin
  if not (FCurrentState = AState) then
    FCurrentState := AState;
  FOnStateChange.DispatchEvent(Self);
end;

function TGLGUIObject.GetBasicState: TGLGUIState;
begin
  Result := FBasicState;
end;

procedure TGLGUIObject.SetBasicState(const AState: TGLGUIState);
begin
  if not (FBasicState = AState) then
    FBasicState := AState;
end;

function TGLGUIObject.GetEventBehaviour(): TGLGUIEventBehaviour;
begin
  Result := FEventBehaviour;
end;

procedure TGLGUIObject.SetEventBehaviour(AEventBehaviour: TGLGUIEventBehaviour);
begin
  FEventBehaviour := AEventBehaviour;
end;

function TGLGUIObject.GetEnabled: Boolean;
begin
  Result := FEnabled;
end;

function TGLGUIObject.GetIsOnFocus: Boolean;
begin
  Result := GUIEventManager.FocusedObject = Self;
end;

procedure TGLGUIObject.SetEnabled(AEnabled: Boolean);
begin
  if AEnabled = True then
    Enable
  else
    Disable;
  FEnabled := AEnabled;
end;

procedure TGLGUIObject.SetTransmitEnableState(ADoEnable: Boolean);
begin
  FTransmitWorkState := ADoEnable;
end;

function TGLGUIObject.GetTransmitEnableState: Boolean;
begin
  Result := FTransmitWorkState;
end;

function TGLGUIObject.GetListenersOverwriting: Boolean;
begin
  Result := FListenersOverwriting;
end;

procedure TGLGUIObject.SetListenersOverwriting(AOverwrite: Boolean);
begin
  FListenersOverwriting := AOverwrite;
end;

function TGLGUIObject.GetRenderMode: TGLGUIRenderMode;
begin
  Result := FRenderMode;
end;

function TGLGUIObject.GetId: Cardinal;
begin
  Result := FID;
end;

procedure TGLGUIObject.SetID(AID: Cardinal);
begin
  FID := AID;
end;

function TGLGUIObject.GetCursorImage: SmallInt;
begin
  Result := FCursorImage;
end;

procedure TGLGUIObject.SetCursorImage(AImage: SmallInt);
begin
  FCursorImage := AImage;
end;

procedure TGLGUIObject.AddEventBind(AEvent: TGLGUIEvent; AListener: TGLGUIEventListener; var ABind: TGLGUIEventListenerBind);
begin
  if not Assigned(ABind) then
  begin
    ABind := AddEventListener(AEvent, AListener);
  end else
  begin
    if FListenersOverwriting then
      ABind.Listener := AListener
    else
      AddEventListener(MouseDownEvent, AListener)
  end;
end;

procedure TGLGUIObject.SetOnMouseDown(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(MouseDownEvent, AEventListener, FOnMouseDown);
end;

procedure TGLGUIObject.SetOnMouseUp(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(MouseUpEvent, AEventListener, FOnMouseUp);
end;

procedure TGLGUIObject.SetOnMouseMove(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(MouseMoveEvent, AEventListener, FOnMouseMove);
end;

procedure TGLGUIObject.SetOnMouseEnter(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(MouseEnterEvent, AEventListener, FOnMouseEnter);
end;

procedure TGLGUIObject.SetOnMouseLeave(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(MouseLeaveEvent, AEventListener, FOnMouseLeave);
end;

procedure TGLGUIObject.SetOnKeyDown(AEventListener: TGLGUIEventListener);
begin
  AddEventBind(KeyDownEvent, AEventListener, FOnKeyDown);
end;

procedure TGLGUIObject.Enable;
var
  i: Integer;
begin
  if State = GLGUIDisabled then
    SetState(GLGUIEnabled);
  FEnabled := True;
  if FTransmitWorkState then
    for i := 0 to Count - 1 do
    if Children[i] is TGLGUIObject then
      TGLGUIObject(Children[i]).Enabled := FEnabled;
end;

procedure TGLGUIObject.Disable(AKeepState: Boolean = False);
var
  i: Integer;
begin
  if not AKeepState then
    SetState(GLGUIDisabled);
  FEnabled := False;
  if FTransmitWorkState then
    for i := 0 to Count - 1 do
    if Children[i] is TGLGUIObject then
      TGLGUIObject(Children[i]).Enabled := FEnabled;
end;

procedure TGLGUIObject.SetFocus();
begin
  GUIEventManager.FocusedObject := Self;
end;

destructor TGLGUIObject.Destroy();
var
 i : Integer;
begin
  FEnabled := False;
  FProgressEvent.Free;
  if GUIEventManager.FocusedObject = Self then
    GUIEventManager.FocusedObject := nil;
  if GUIEventManager.HighLitedObject = Self then
    GUIEventManager.HighLitedObject := nil;
  for i := 0 to FRegistredEvents.Count - 1 do
    FRegistredEvents.Items[i].RemoveListeners(FRegistredBinds);
  FRegistredBinds.Free;
  FRegistredEvents.Free;
  inherited;
end;

end.
